home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d8 / zmax.arc / ZMAX.C < prev    next >
C/C++ Source or Header  |  1990-07-23  |  47KB  |  1,409 lines

  1. /*
  2.  
  3. This is a full functional, tested, driver. I've attempted to keep
  4. the code as simple as possible and use terms that anyone thats
  5. written any type of protocol knows since its to be used as a guide
  6. to other implementations.
  7.  
  8. Zmax was designed with reliablity in mind as the FIRST and foremost
  9. concern, speed came in a close second. You'll no doubt notice a couple
  10. of areas where it could be speeded up and I was tempted. Zmax isn't
  11. the FASTEST protocol around, but then it wasn't suppose to be.
  12.  
  13. I wanted the best all round protocol which would always get the file
  14. there intact and as quickly as possible. I beleive you'll be very hard
  15. pressed to find any protocol that will best Zmax in RELIABLITY, FLEXABLITY,
  16. and SPEED.
  17.  
  18. */
  19.  
  20. /* Include files */
  21.  
  22. #include<stdio.h>
  23. #include "zmax.h"
  24. #include<malloc.h>
  25. #include<filedata.h>
  26. #include<comm.h>
  27. #include<ctype.h>
  28.  
  29. /* Globle Declares */
  30. FILE *out;
  31. unsigned long UpdCrc32(char byte, unsigned long crc);
  32. long file_position,seof;
  33. int cancel,percent_size,total_errors = 0,endsend = 0,delete_aborted_transfers = 1;
  34. struct filedata filstruc;
  35. long locked_port, atol(), timerset(),amt_sent;
  36. char *Screen_ptr;
  37. char acks_required;
  38. char tbuf[2048],junk_string[81];
  39. int block_len,return_code = 1,port_ptr;
  40. unsigned cur_baud,connect_rate,sending_file;
  41. ASYNC *port;
  42. int     IOadrs = 0x3f8;                      /* comm port base I/O address */
  43. char    irqm = IRQ4;                         /* mask for selected IRQ line */
  44. char    vctrn = VCTR4;                        /* comm interrupt vector nbr */
  45. char log_file[81];
  46.  
  47. /* Zmax Structures */
  48.  
  49. struct Zhead                           /* File info data structure */
  50. {   long flen;                         /* file length */
  51.     unsigned fdate;                    /* Files DATE stamp, DOS format */
  52.     unsigned ftime;                    /* Files TIME stamp, DOS format */
  53.     char fnam[14];                     /* original file name */
  54. }   ;
  55.  
  56. struct _block_header
  57.   {
  58.    long position;
  59.    unsigned bytes;
  60.    char ack; /* If on (set to 1) the receiver must
  61.                       ACK data block if good. */
  62.   };
  63.  
  64. struct _info_header
  65.  {
  66.   unsigned flags;
  67.   /* 00000000 00000001 = Can handle Continues Stream Transmissions.
  68.  
  69.                          If this flag is off, ACK is required following
  70.                          each block of data.
  71.  
  72.                          ACKING each block of data turns Zmax into a
  73.                          X/Ymodem Batch type protocol.
  74.  
  75.                          It is suggested that once you reach 128
  76.                          byte blocks, bad lines, Zmax should
  77.                          require each block of data to be ACKED.
  78.  
  79.                          This  will switch it to a batch
  80.                          Xmodem style protocol which is
  81.                          better for bad phone lines.
  82.  
  83.                          You'll also notice that although there are
  84.                          provisions for decreasing the block size
  85.                          when noisy lines are encountered, you don't
  86.                          see any place where I raise the block size back
  87.                          up.
  88.  
  89.                          There is nothing saying you CAN'T do that, I just
  90.                          don't beleive you should. If you encounter
  91.                          enough noise to cause the block size to drop, then
  92.                          the likely hood of you encountering MORE is very high.
  93.  
  94.                          You'll also notice that I do not drop the block size
  95.                          on the first error. One error does not make for bad
  96.                          phone lines, 2 or more does.
  97.  
  98.                          */
  99.   int   buf_size;      /* Used to pass transmitter the receivers max
  100.                         buffer size. Its is suggested that the receiver
  101.                         support 2K buffer.
  102.  
  103.                         The transmitter doesn't have to give you those
  104.                         sizes and can replace them with his own as long
  105.                         as it is less than or equal to your max buffer
  106.                         size.
  107.  
  108.                         Nor do the block sizes have to be powers of 2.
  109.  
  110.                         You can use odd block sizes...231, 888, etc.
  111.  
  112.                         I used powers of 2 because of the way DOS formats
  113.                         harddrives, ie. cluster size.
  114.  
  115.                         You'll also notice that Zmax places little restrictions
  116.                         on the maximum SIZE of the block although going over
  117.                         2048 shows little gain and lots of loses when a resend
  118.                         is requested.
  119.  
  120.                         To give you some guidelines for setting block sizes
  121.                         see chart below:
  122.  
  123.                         Chart based on sending a 60,416 byte file WITH the
  124.                         protocol overhead figured in and driving the serial
  125.                         port to its maximum Cps at that baud rate which this
  126.                         driver does.
  127.  
  128.                         Blk Size                     Tx Time
  129.                          Bytes                    2400    9600 LOCKED Port.
  130.  
  131.                           64                      318.60  79.65
  132.                          128                      285.17  71.29
  133.                          256                      268.45  67.11
  134.                          512                      260.09  65.02
  135.                         1024                      255.91  63.98
  136.                         2048                      253.82  63.46
  137.                         4096                      252.78  63.20
  138.                         8192                      252.26  63.07
  139.  
  140.                         As you can see, there's quite a bit of savings
  141.                         across the baud rate scale with each increament
  142.                         of the block size up to 2048 bytes. Once you exceed
  143.                         2048 BPB, the savings is almost not measureable.
  144.  
  145.                         Taking into account the time required to resend 2K of
  146.                         data at 2400 bps, I wouldn't risk going over 1K at 2400
  147.                         unless the call is local or under MNP.
  148.  
  149.                         You may REQUEST any size data block up to
  150.                         the size of a signed integer.
  151.  
  152.  
  153.                         */
  154.    unsigned char version ; /*
  155.  
  156.                      This allows for future expansion to the protocol
  157.                      and still yet allow for backwards compatibly.
  158.  
  159.                      This is the version of the protocol specs that the
  160.                      receiver supports. Currently this should be set to one.
  161.  
  162.                    */
  163.   char empty[123]; /* Reserves an extra 123 bytes for future expansion */
  164.  };
  165.  
  166. /* DEFINES */
  167.  
  168. #define STX 2
  169. #define TSYNCH 0xae
  170. #define ACK 0x06
  171. #define NAK 0x15
  172. #define SOH 0x01
  173. #define EOT 0x04
  174. #define CAN 0x18
  175. #define RESYNC 9
  176. #define PER_WEEK  60480000L
  177. #define PER_DAY    8640000L
  178. #define PER_HOUR    360000L
  179. #define PER_MINUTE    6000L
  180. #define PER_SECOND     100L
  181. #define ENQ 0x05
  182.  
  183. main(int argc, char *argv[])
  184. {
  185. /*
  186.  
  187.    This is the main section of this driver. It's makeup is entirely
  188.    up to you. With of course, several REQUIRED sets.
  189.  
  190.    */
  191. int i,x,count;
  192. int y=0,block_size=1024;
  193. int send=0,do_acks=0;
  194. char s[81],s1[81];
  195. qvideo();
  196. clrscrn();
  197. Screen_ptr = malloc(1 * 4000);
  198. if(Screen_ptr == NULL) exit(1);
  199. uncomprs(&Screen_ptr[0*4000], tmod); /* uncompress screen 1 */
  200. memtoscr(2000, 0, Screen_ptr);
  201. curoff();
  202. memset(s,'\0',sizeof(s));
  203. if(!envget2("OSIRIS",s))
  204.    sprintf(log_file,"%s\\Zmax.log",s);
  205. else
  206.    sprintf(log_file,"Zmax.log");
  207. for(i=1;i<argc;i++)
  208.  {
  209.   if(argv[i][0] == '/' || argv[i][0] == '-')
  210.   {
  211.     switch(toupper(argv[i][1]))
  212.     {
  213.     case 'S' : block_size = atoi(argv[i+1]);
  214.                if(block_size > 2048)
  215.                              block_size = 2048;
  216.                break;
  217.     case 'A' : do_acks = 1;break;
  218.     case 'K' : delete_aborted_transfers = 0;
  219.                break;
  220.     case 'P' : port_ptr = atoi(argv[i+1]);
  221.                port_ptr--;
  222.                break;
  223.     case 'B' : connect_rate = atoi(argv[i+1]);
  224.                cur_baud = connect_rate;
  225.                block_size = (connect_rate > 2400) ? 2048 : 1024;
  226.                break;
  227.     case 'L' : locked_port = atol(argv[i+1]);
  228.                break;
  229.     case 'R' : set_com();
  230.  
  231.                /*
  232.                  You should continue to cycle receiving files until
  233.                  Zrecfile returns a ZERO, indicating that it did not
  234.                  receive any files or the session was aborted.
  235.                  */
  236.  
  237.                while ( Zrecfile(do_acks,block_size) && (async_carrier(port))) clear_screen() ;
  238.  
  239.                /* Following the last file, the sender will require an ACK
  240.                   to signal the receivers acknowledges end of session.
  241.  
  242.                   The Sender doesn't respond back after receiving the ACK so
  243.                   continue with you processing after sending a couple of
  244.                   ACKS. Two is suggested, an extra incase line noise blew the
  245.                   first one.
  246.                   */
  247.  
  248.                com_putc(ACK);
  249.                com_putc(ACK);
  250.                end_prg();
  251.                break;
  252.  
  253.     case 'F' : set_com();
  254.                i++;
  255.                for(;i<argc;i++)
  256.                 {
  257.                  memset(s,'\0',sizeof(s));
  258.                  parser(argv[i],&s[0]);
  259.  
  260.                  /* Cycle until all files are sent or Zsendfile returns
  261.                     a zero indicating Session was aborted. */
  262.  
  263.                  if(!Zsendfile(argv[i],s))
  264.                        end_prg();
  265.                  if(!async_carrier(port)) end_prg();
  266.                  clear_screen();
  267.                 }
  268.                 i = count = 0;
  269.  
  270.                 /* Cycle sending EOT until receiver sees it and ACKs
  271.                     the ending EOT. I suggest cycling only two periods
  272.                     , period being defined as trying ACKEOT function twice. */
  273.  
  274.                 while(!count && i <= 1)
  275.                   {
  276.                    com_putc(EOT);
  277.                    i++;
  278.                    if(ackeot()) count = 1;
  279.                    if(!async_carrier(port)) count = 1;
  280.                   }
  281.                 end_prg();
  282.                 break;
  283.    }
  284.  }
  285.  }
  286.  
  287. }
  288. Zsendfile(name,s_name)                      /* transmit a file */
  289. char *name;           /* FULL Drive, path, and name of file to send */
  290. char s_name[]; /*   Only the filename, fit to be used in  file info
  291.                       header.
  292.                  */
  293.  
  294.  
  295. {
  296.     long location, blkloc,last_location,t4,size,st,ft,t1,t2,t3;
  297.     int error=0,endblk,x,y,i,cps;
  298.     struct Zhead zero;
  299.     struct _info_header info_header;
  300.     unsigned file_date,file_time,actual;
  301.     char s[80];
  302.     int ok;
  303.     struct _block_header block_header;
  304.     if(!async_carrier(port)) return(0);
  305.     acks_required = 1;
  306.     async_txflush(port);
  307.     file_position = 0L;
  308.  
  309.          if(!filexist(name)) return(1);
  310.  
  311.          x = openfil(name,2,&sending_file);
  312.          getstamp(sending_file,&file_date,&file_time);
  313.          memset(&zero,'\0',sizeof(zero)); /* clear out data block */
  314.          filsize(name,&size);
  315.          percent_size = size / 40;
  316.          seof = size;
  317.          strcpy(zero.fnam,s_name);
  318.          zero.fdate = (unsigned) file_date;
  319.          zero.ftime = (unsigned) file_time;
  320.          zero.flen =  (long) size;
  321.          curlocat(5,28);
  322.          colrprtf(0,0,7,"%-14s",zero.fnam);
  323.          curlocat(6,28);
  324.          colrprtf(0,0,7,"%-7ld",size);
  325.          amt_sent = 0L;
  326.  
  327.          total_errors =  cancel =   0;
  328.          t1 = timerset(6000L);                /* time limit for first block */
  329.          com_putc(TSYNCH);
  330.          com_putc(TSYNCH);
  331.          endsend = i = 0;
  332.          while(x != 'C' && !timeup(t1)) /* Wait for primer start */
  333.           {
  334.            x = com_getc(2);
  335.            if(x != 'C')
  336.                com_putc(TSYNCH);
  337.            if(!async_carrier(port)) return(0);
  338.            if(x == 0x18) cancel++;
  339.            if(cancel > 3)
  340.             {
  341.              curlocat(7,28);
  342.              colrprtf(0,0,7,"%-40s","Rcv Canceled Transfer");
  343.              closefil(sending_file);
  344.              end_prg();
  345.             }
  346.           }
  347.           cancel = 0;
  348.           if(x != 'C')
  349.                 goto abort; /* If we did not get it then abort */
  350.  
  351.           ok = 0;
  352.           while(!get_system_info(&info_header) && async_carrier(port))
  353.             {
  354.             if(++ok > 3)
  355.                async_dtr(port,0); /* After 3 attempts, drop carrier
  356.                                      and bail out.
  357.                                   */
  358.             }
  359.           if(!async_carrier(port)) goto abort;
  360.  
  361.           block_len = info_header.buf_size;
  362.           if(block_len > 2048)
  363.                        block_len = 2048;
  364.           if( (info_header.flags&0x0001))
  365.                            acks_required = 0;
  366.           cancel = ok = 0;
  367.  
  368.           curlocat(7,28);
  369.           colrprtf(0,0,7,"%-40s","Sending File Header");
  370.        while(!ok)
  371.        {
  372.           async_rxflush(port);
  373.           SendHeader(&zero);
  374.           switch(wait_ack())
  375.                {
  376.                        case 1:  break;
  377.  
  378.                        case 2:
  379.                                closefil(sending_file);
  380.                                curlocat(7,28);
  381.                                colrprtf(0,0,7,"%-40s","Rcv Already has File");
  382.                                return(1);
  383.                        case 3:/* REPOS ie. Restart */
  384.                        default: curlocat(7,28);
  385.                                 sprintf(junk_string,"BufSize %d (%sStream Mode)",info_header.buf_size,(acks_required) ? "Non-" : "");
  386.                                 colrprtf(0,0,7,"%-40s",junk_string);
  387.                                 ok = 1;
  388.                                 break;
  389.  
  390.                 }/* End switch  */
  391.      }
  392.  
  393.     st = timerset(0L);
  394.     async_rxflush(port);
  395.     async_txflush(port);
  396.     do
  397.     {
  398.               if( !async_carrier(port) )
  399.                   goto abort;
  400.               if(timeup(t1))
  401.                   goto abort;
  402.               if(checkkey())
  403.                       {
  404.                       i = getkey(&x);
  405.                        if(x == 27)
  406.                          {
  407.                              while(!async_txempty(port)){
  408.                                     if(!async_carrier(port)) break;
  409.                                     }
  410.                              cancel_transfer();
  411.                              goto abort;
  412.                         }
  413.                        }
  414.               while(file_position < zero.flen)/* loop until all sent */
  415.               {
  416.                        if(!async_carrier(port))
  417.                                         goto abort;
  418.                        ChkForNak();
  419.                        if(checkkey())
  420.                        {
  421.                          i = getkey(&x);
  422.                          if(x == 27)
  423.                          {
  424.                              while(!async_txempty(port)){
  425.                                     if(!async_carrier(port)) break;
  426.                                     }
  427.                              cancel_transfer();
  428.                              goto abort;
  429.                         }
  430.                        }
  431.                        /*
  432.                          NOTE: My file functions; seekfil,
  433.                          readfil, creatfil, openfil, writefil,
  434.                          etc. all have built in error handling
  435.                          routines to reduce redundent coding on
  436.                          MY part. You should add your own error
  437.                          trapping according to what your using.
  438.  
  439.                          */
  440.                        i = seekfil(sending_file,0,file_position,&location);
  441.                        i = readfil(sending_file,block_len,tbuf,&actual);
  442.  
  443.  
  444.                        /*
  445.                           Sending the current file position with
  446.                           each data block removes all
  447.                           possiblities of Desqview shifting the
  448.                           file position, a network or satellite
  449.                           link miss routing or losing a block of
  450.                           data. I've seen both happen before and
  451.                           they weren't detected until the end of
  452.                           file.
  453.  
  454.                           This totally insures that the receiver
  455.                           and sender are never out of sync.*/
  456.  
  457.                        last_location = block_header.position = file_position;
  458.                        block_header.bytes = actual;
  459.                        block_header.ack = (acks_required) ? 1 : 0 ;
  460.                        file_position = (long) file_position + (long) actual;
  461.                        amt_sent = (long) file_position;
  462.                        com_putc(SOH);
  463.                        com_putc(ENQ);
  464.                        send_block_header(&block_header);
  465.                        SendDataBlock(tbuf,actual);
  466.                        if(block_header.ack)
  467.                         {
  468.                           i = com_getc(10);
  469.                           if(i != ACK){
  470.                                 file_position = last_location;
  471.                                 curlocat(7,28);
  472.                                 sprintf(junk_string,"REPOS %ld",file_position);
  473.                                 colrprtf(0,0,7,"%-40s",junk_string);
  474.                                 curlocat(5,58);
  475.                                 colrprtf(0,0,7,"%d",++total_errors);
  476.                                 }
  477.                         }
  478.                        else
  479.                           ChkForNak();
  480.                        if(file_position == zero.flen)
  481.                        {
  482.                            com_putc(EOT);
  483.                            endsend = 0;
  484.                            t1 = timerset(9000L);  /* time limit for last block if ackless(90 secs) */
  485.                            sprintf(junk_string,"%-7ld",zero.flen);
  486.                            curlocat(6,58);
  487.                            colrprtf(0,0,7,"%s",junk_string);
  488.                            for(i=1;i<=40;i++)
  489.                            {
  490.                               curlocat(19,(21+i));
  491.                               colrprtf(0,15,7,"█");
  492.                            }
  493.                         }
  494.                         ChkForNak();
  495.                         if(cancel >= 5) goto abort;
  496.               }/* Still to go */
  497.               ChkForNak();
  498.               if(cancel >= 5) goto abort;
  499.  
  500.     }while(!endsend);
  501.     /* end main send */
  502.  
  503.     ft = timerset(0L);
  504.     closefil(sending_file);
  505.       ft = (long) (ft-st) / 100L;
  506.       if(ft == 0) ft = 1L;
  507.       cps = (int) (zero.flen / ft);
  508.       x = (cps*10) / (connect_rate/100);
  509.       curlocat(14,28);
  510.       colrprtf(0,0,7,"%3d%%",x);
  511.       out = fopen(log_file,"a");
  512.       fprintf(out,"%d bps   %-14s   %-7ld   %3d%%\n",connect_rate,zero.fnam,zero.flen,x);
  513.       fclose(out);
  514.       return_code = 0;
  515.       return(1);                          /* exit with good status */
  516.  
  517. abort:
  518.     async_txflush(port);
  519.     closefil(sending_file);
  520.     return(0);                          /* exit with bad status */
  521. }
  522.  
  523.  
  524. ChkForNak()                        /* check for bad block */
  525. {
  526.     unsigned char c=0;
  527.     int q;
  528.     struct _block_header block_header;
  529.  
  530.     top:;
  531.       c = com_getc(0);
  532.       if(c == 'C' || c == ACK)
  533.        {
  534.         if(c == ACK)
  535.              {
  536.              if(file_position == seof)
  537.                               endsend = 1;
  538.              return;
  539.              }
  540.         q = com_getc(0);
  541.         if(q != '*')
  542.                   return;
  543.         if(get_block_header(&block_header))
  544.         {
  545.  
  546.               /* There really isn't any need to validate
  547.                  the file position since the block function is
  548.                  protected with its own 32 bit CRC. The likely
  549.                  hood of it being incorrect is so remote....*/
  550.  
  551.               file_position = block_header.position;
  552.               curlocat(7,28);
  553.               sprintf(junk_string,"REPOS %ld",file_position);
  554.               colrprtf(0,0,7,"%-40s",junk_string);
  555.               curlocat(5,58);
  556.               colrprtf(0,0,7,"%d",++total_errors);
  557.               if(total_errors > 1 && block_len > 128)
  558.                                          block_len >>= 1;
  559.               if(block_len == 128 && !acks_required)
  560.                                          acks_required = 1;
  561.         }
  562.      }
  563.       else
  564.        if(c == CAN)
  565.              cancel++;
  566.  
  567. if( (async_rxcnt(port)))
  568.        goto top;
  569. }
  570.  
  571. SendDataBlock(blk,size)         /* physically ship a block */
  572. char *blk;                             /* data to be shipped */
  573. int size;/* size of block */
  574. {
  575. register i,x,y;
  576. unsigned long oldcrc;
  577. long location;
  578. static unsigned char ch;
  579. char *b = blk;
  580. char *j = blk;
  581. static int n,q,flow,aa,kk;
  582.  
  583.  
  584.           while(  (async_txblk(port, b, size)) == R_TXERR)
  585.           {
  586.                 curlocat(6,58);
  587.                 location = (long) file_position - size;
  588.                 colrprtf(0,0,7,"%-7ld",location);
  589.                 kk = location / percent_size;
  590.                 if(kk > 40) kk = 40;
  591.                 for(aa=1;aa<=kk;aa++)
  592.                            {
  593.                               curlocat(19,(21+aa));
  594.                               colrprtf(0,15,7,"█");
  595.                            }
  596.                 if(async_rxcnt(port))
  597.                 {
  598.                   flow = (async_peek(port,0)&0xff);
  599.                   if(flow == 'C')
  600.                    {
  601.                       async_txflush(port);
  602.                       return;
  603.                    }
  604.                    else
  605.                      if(flow != CAN)
  606.                           flow = async_rx(port); /* Eat non C/CAN char, more
  607.                                                     than likely was line noise
  608.                                                      */
  609.                 }
  610.                 else
  611.                   if(!async_carrier(port)) return;
  612.  
  613.          }/* end while*/
  614.           oldcrc = 0xFFFFFFFF;
  615.           for(n=0;n<size;n++){
  616.                   oldcrc = UpdCrc32(((unsigned short) (*j++)), oldcrc);
  617.                   }
  618.           oldcrc = ~oldcrc;
  619.         for(n=4; --n >=0;)
  620.         {
  621.           com_putc((unsigned char) oldcrc);
  622.            oldcrc >>= 8;
  623.         }
  624.         if(acks_required)
  625.         {
  626.                 curlocat(6,58);
  627.                 location = (long) file_position - size;
  628.                 colrprtf(0,0,7,"%-7ld",location);
  629.                 kk = location / percent_size;
  630.                 if(kk > 40) kk = 40;
  631.                 for(aa=1;aa<=kk;aa++)
  632.                            {
  633.                               curlocat(19,(21+aa));
  634.                               colrprtf(0,15,7,"█");
  635.                            }
  636.         }
  637. }
  638.  
  639. ackeot()
  640. {
  641. long t;
  642. int c;
  643. t = timerset(300L);
  644. while(!timeup(t))
  645. {
  646. c = com_getc(0);
  647.     if(c == ACK)
  648.             return(1);
  649. }
  650.  
  651. return(0);
  652. }
  653. long timerset (t)
  654. long t;
  655. {
  656.         long l;
  657.         int l2;
  658.         int hours,mins,secs,ths,year,month,day;
  659.  
  660.         sysitime (&hours,&mins,&secs,&ths);
  661.         sysidate(&year,&month,&day);
  662.         l2 = dayofwee(year,month,day);
  663.  
  664.         l =     l2      * PER_DAY       +
  665.                 hours   * PER_HOUR      +
  666.                 mins    * PER_MINUTE    +
  667.                 secs    * PER_SECOND    +
  668.                 ths                     ;
  669.  
  670.         l += t;
  671.  
  672.         return (l);
  673.         }
  674.  
  675. timeup (t)
  676. long t;
  677. {
  678.         long l;
  679.  
  680.         l = timerset (0L);
  681.         if(l < (t-PER_DAY)) l = l + PER_DAY;
  682.         return ((l - t) >= 0L);
  683.         }
  684.  
  685. com_getc(t)
  686. int t;
  687. {
  688.         static long t1,t2;
  689.         int c;
  690.         if(!((c = async_rx(port)) & B_RXEMPTY))
  691.                return((c&0xff));
  692.         t2 = (long) t * 100L;
  693.         t1 = timerset (t2);
  694.         while(((c = async_rx(port)) & B_RXEMPTY))
  695.                 {
  696.                 if(!async_carrier(port))
  697.                     {
  698.                     return(EOF);
  699.                     }
  700.                 if (timeup(t1))
  701.                         {
  702.                         return(EOF);
  703.                         }
  704.                 }
  705.         return((c&0xff));
  706.  
  707.  
  708.         }
  709. wait_ack()
  710. {
  711. int ch;
  712. long t;
  713. struct _block_header block_header;
  714.  
  715. t = timerset(3000L); /* If no rsponds in 30 seconds, skip file */
  716. for(;;)
  717.  {
  718.     ch = com_getc(5);
  719.     if(ch == 'D')
  720.       {
  721.             ch = com_getc(5);
  722.             if(ch == 'P')
  723.             {
  724.                com_putc(ACK);
  725.                return(2);
  726.             }
  727.       }/* End if Duplicate File */
  728.  
  729.     if(ch == ACK) return(4);
  730.  
  731.    if(ch == CAN || timeup(t))
  732.     {
  733.        async_rxflush(port);
  734.        return(2);
  735.     }
  736.  
  737.     if(ch == RESYNC)
  738.     {
  739.       if(get_block_header(&block_header))
  740.         {
  741.           file_position = block_header.position;
  742.           return(3);
  743.         }
  744.  
  745.     }/* Resync */
  746.  
  747.    if(ch == 'C')
  748.          return(1);
  749.  }
  750.  
  751. }
  752.  
  753. SendHeader(blk)                      /* physically ship Fileinfo block */
  754. char *blk;                             /* data to be shipped */
  755. {
  756. register ch,n;
  757. unsigned long oldcrc;                  /* CRC check value */
  758.  
  759.     com_putc(SOH);
  760.     com_putc(NAK);
  761.  
  762.     while(  (async_txblk(port, blk, 22)) == R_TXERR);
  763.  
  764.          oldcrc = 0xFFFFFFFF;
  765.           for(n=0;n<22;n++){
  766.                   oldcrc = UpdCrc32(((unsigned short) (*blk++)), oldcrc);
  767.                   }
  768.           oldcrc = ~oldcrc;
  769.         for(n=4; --n >=0;)
  770.         {
  771.           com_putc((unsigned char) oldcrc);
  772.            oldcrc >>= 8;
  773.         }
  774.  
  775. }
  776.  
  777. set_com()
  778. {
  779. char parms[80],s2[30],s3[30];
  780. int ch;
  781. long atol();
  782. if(port_ptr)
  783.    {
  784.    IOadrs = 0x2f8;
  785.    irqm = 0x08;
  786.    vctrn = 11;
  787.    }
  788. port = malloc(sizeof(ASYNC));
  789. sprintf(s3,"COM%d",port_ptr+1);
  790. memset(s2,'\0',sizeof(s2));
  791. if(!envget2(s3,s2))
  792.     locked_port = (long) atol(s2);
  793. if(locked_port)
  794. sprintf(parms,"%ldN81",locked_port);
  795. else
  796. sprintf(parms,"%dN81",cur_baud);
  797. if(!(AllocRingBuffer(port, 2048, 3072, 1)))/* Note that I allocate
  798.                                               a TX buffer 1K larger
  799.                                               than the largest block
  800.                                               size that I support.
  801.  
  802.                                               This gives me a little
  803.                                               breathing space in STREAM
  804.                                               mode at 9600+ for file management. */
  805.    exit(0);
  806. if ((ch = async_open(port, IOadrs, irqm, vctrn, parms)) != R_OK)
  807.           exit(0);
  808. async_rxflush(port);
  809. async_txflush(port);
  810. async_msrflow(port, B_CTS);
  811. async_FIFOtxlvl(port,4);/*
  812.                            I strongly suggest that you keep the
  813.                            FIFO Tx bytes per interrupt to no more
  814.                            than 4.
  815.  
  816.                            Reason:
  817.  
  818.                            This driver will drive the modem so
  819.                            fast and hard that an HST 450
  820.                            Backchannel will loose its sync with
  821.                            an HST Dual Standard or HST 14.4 if
  822.                            its (450) doing the sending.
  823.  
  824.  
  825.                         */
  826. async_FIFOrxlvl(port,1);/* Never go over 1 here */
  827. }
  828.  
  829. parser(s,name) char s[],name[];
  830. {
  831. char stack[80];
  832. int i,x;
  833. if(strindex("\\",s) == -1)
  834.  {
  835.   name[0] = 0;
  836.   strcpy(name,s);
  837.   return;
  838.  
  839.  }
  840.  
  841. memset(stack,'\0',sizeof(stack));
  842. x = strlen(s);
  843. i = 0;
  844. while(s[x] != '\\' && x > 0)
  845.   {
  846.   if(s[x] != 0 && s[x] != 13 && s[x] != 10) stack[i++] = s[x];
  847.   x--;
  848.   }
  849. x = 0;
  850. i--;
  851. while(i >= 0)
  852.    name[x++] = stack[i--];
  853. name[x] = '\0';
  854. }
  855.  
  856. end_prg()
  857. {
  858. curon();
  859. if(async_carrier(port))
  860.      port->OldMCR |= B_DTR;
  861. async_close(port);
  862. if(!delete_aborted_transfers)
  863.   sleep(20);
  864. exit(return_code);
  865.  
  866. }
  867.  
  868. Zrecfile(int do_acks,int block_size)                    /* receive file */
  869. {
  870.     int n,w,x,y,tries,i,c,cps;
  871.     char outname[81];
  872.     int kk,aa;
  873.     unsigned send,actual,file_date,file_time;
  874.     struct Zhead zero;                 /* file header data storage */
  875.     struct _block_header block_header;
  876.     struct _info_header SystemInfo;
  877.     long t1,st,ft,lsize,testl;
  878.  
  879.     tries = total_errors = c = 0;
  880.     percent_size = 32000;
  881.     memset(outname,'\0',sizeof(outname));
  882.     memset(&zero,'\0',sizeof(zero));
  883.     amt_sent = 0L;
  884.     file_position = 0L;
  885.     st = timerset(6000L);
  886.     com_putc(' ');
  887.  
  888.     while(!timeup(st))
  889.     {
  890.          if(!async_carrier(port))
  891.                           return(0);
  892.      c = com_getc(1);
  893.      if(c == TSYNCH)
  894.          st =timerset(0L);
  895.      if(c == EOT)
  896.          return(0);
  897.     }
  898.     if(c != TSYNCH)
  899.      {
  900.          curlocat(7,28);
  901.          colrprtf(0,0,7,"%-40s","Sender flobbed it");
  902.          st = timerset(500L);
  903.          while(!timeup(st)) ;
  904.          return(0);
  905.      }
  906.  
  907.     cancel = c = 0;
  908.     st = 0L;
  909.     com_putc('C');
  910.     c = '\0';
  911.     memset(&SystemInfo,'\0',sizeof(SystemInfo));
  912.     if(!do_acks)
  913.        SystemInfo.flags ^= 0x0001;
  914.     SystemInfo.buf_size =  block_size;
  915.     SystemInfo.version = 1;
  916.  
  917.     send_system_info(&SystemInfo);
  918.  
  919.     curlocat(7,28);
  920.     colrprtf(0,0,7,"%-40s","Waiting For File");
  921.  
  922.     goto nextblock;
  923.  
  924. badblock:                              /* we got a bad block */
  925.  
  926.     if(++tries>4)
  927.     {
  928.          async_dtr(port,0);
  929.          sleep(3);
  930.          async_dtr(port,1);
  931.          goto abort;
  932.     }
  933.     if(!block_header.ack)
  934.     {
  935.     async_rxflush(port);
  936.     com_putc('C');
  937.     com_putc('*');
  938.     block_header.position = file_position;
  939.     send_block_header(&block_header);
  940.     async_rxflush(port);
  941.     }
  942.     else
  943.       com_putc('C');
  944.     i = seekfil(send,2,0L,&testl);
  945.     curlocat(7,28);
  946.     sprintf(junk_string,"REPOS %ld",file_position);
  947.     colrprtf(0,0,7,"%-40s",junk_string);
  948.     curlocat(5,58);
  949.     colrprtf(0,0,7,"%d",++total_errors);
  950.     goto nextblock;
  951.  
  952. goodblock:                              /* we got a good block */
  953.  
  954.     if(block_header.ack)
  955.                  com_putc(ACK);
  956.     amt_sent = (long) file_position;
  957.  
  958. nextblock:                             /* start of "get a block" */
  959.     t1 = timerset(2000L);
  960.     while(!timeup(t1))
  961.     {
  962.          if(checkkey())
  963.          {
  964.           aa = getkey(&kk);
  965.           if(kk == 27)
  966.            {
  967.             cancel_transfer();
  968.             goto abort;
  969.            }
  970.          }
  971.          c = (com_getc(3)&0xff);
  972.          switch (c)
  973.          {
  974.          case CAN : cancel++;
  975.                     if(cancel >= 5)
  976.                            goto abort;
  977.                     break;
  978.          case SOH :
  979.                         x = com_getc(5);
  980.                         switch(x)
  981.                            {
  982.                               case NAK :
  983.                                             if(readblock(&zero,22))
  984.                                               {
  985.                                                      st = timerset(0L);
  986.                                                      sprintf(outname,"%s",zero.fnam);
  987.                                                      if(!filexist(outname))
  988.                                                                  com_putc(ACK);
  989.                                                         if(filexist(outname))
  990.                                                           {
  991.                                                              openfil(outname,2,&send);
  992.                                                              getstamp(send,&file_date,&file_time);
  993.                                                              closefil(send);
  994.                                                              filsize(outname,&lsize);
  995.                                                              if(lsize < zero.flen && zero.fdate == file_date && zero.ftime == file_time)
  996.                                                                 {
  997.                                                                      openfil(outname,2,&send);
  998.                                                                      seekfil(send,2,0L,&file_position);
  999.                                                                      curlocat(7,28);
  1000.                                                                      sprintf(junk_string,"Re-Start: %ld",file_position);
  1001.                                                                      colrprtf(0,0,7,"%-40s",junk_string);
  1002.                                                                      com_putc(RESYNC);
  1003.                                                                      block_header.position = file_position;
  1004.                                                                      send_block_header(&block_header);
  1005.                                                                  }
  1006.                                                                  else
  1007.                                                                  {
  1008.                                                                       if(lsize == zero.flen && zero.fdate == file_date && zero.ftime == file_time)
  1009.                                                                        {
  1010.                                                                           x = i = 0;
  1011.                                                                           curlocat(7,28);
  1012.                                                                           colrprtf(0,0,7,"%-40s","Duplicate: Asking for Skip");
  1013.                                                                           async_rxflush(port);
  1014.                                                                           com_putc('D');
  1015.                                                                           com_putc('P');
  1016.                                                                           c = com_getc(5);
  1017.                                                                           if(c == ACK)
  1018.                                                                                return(1);
  1019.  
  1020.                                                                           return(0);
  1021.                                                                        }
  1022.  
  1023.                                                                  }
  1024.                                                          } /* end if exits */
  1025.                                                          else
  1026.                                                              i = creatfil(outname,0,&send);
  1027.                                                          curlocat(5,28);
  1028.                                                          colrprtf(0,0,7,"%-14s",outname);
  1029.                                                          curlocat(6,28);
  1030.                                                          colrprtf(0,0,7,"%-7ld",zero.flen);
  1031.                                                          percent_size  = zero.flen / 40;
  1032.                                                          curlocat(7,28);
  1033.                                                          colrprtf(0,0,7,"%-40s","Getting File");
  1034.  
  1035.                                                          goto goodblock;
  1036.                                                }
  1037.                                                 curlocat(7,28);
  1038.                                                 colrprtf(0,0,7,"%-40s","Bad File Header");
  1039.                                                 com_putc('C');
  1040.                                                 goto nextblock;           /* bad header block */
  1041.                                         break;
  1042.                               case ENQ :memset(&block_header,'\0',sizeof(block_header));
  1043.                                         if(get_block_header(&block_header))
  1044.                                         {
  1045.                                           if(block_header.position != file_position)
  1046.                                            {
  1047.                                                 goto badblock;
  1048.                                            }
  1049.                                            if(readblock(&tbuf[0],block_header.bytes))      /* else if we get it okay */
  1050.                                               {
  1051.                                                  n = writefil(send,block_header.bytes,tbuf,&actual);
  1052.                                                  file_position = (long) file_position + (long) actual;
  1053.                                                  curlocat(6,58);
  1054.                                                  colrprtf(0,0,7,"%-7ld",file_position);
  1055.                                                  tries = 0;
  1056.                                                  kk = file_position / percent_size;
  1057.                                                  if(kk > 40) kk = 40;
  1058.                                                  for(aa=1;aa<=kk;aa++)
  1059.                                                   {
  1060.                                                      curlocat(19,(21+aa));
  1061.                                                      colrprtf(0,15,7,"█");
  1062.                                                   }
  1063.                                                  goto goodblock;
  1064.                                                }
  1065.                                                 goto badblock;
  1066.                                         }
  1067.                                         break;
  1068.                             }/* end switch x*/
  1069.                          break;
  1070.          case EOT :
  1071.                     if(file_position == zero.flen || file_position == 0)
  1072.                     {
  1073.                                 com_putc(ACK);
  1074.                                 if(file_position == 0) return(0);
  1075.                                 ft = timerset(0L);
  1076.                                 sprintf(junk_string,"%-7ld",zero.flen);
  1077.                                 curlocat(6,58);
  1078.                                 colrprtf(0,0,7,"%s",junk_string);
  1079.                                 closefil(send);
  1080.                                 openfil(outname,2,&send);
  1081.                                 setstamp(send,zero.fdate,zero.ftime);
  1082.                                 closefil(send);
  1083.                                  for(i=1;i<=40;i++)
  1084.                                   {
  1085.                                     curlocat(19,(21+i));
  1086.                                    colrprtf(0,15,7,"█");
  1087.                                   }
  1088.                                   ft = (long) (ft - st) /100L;
  1089.                                   if(ft == 0) ft = 1L;
  1090.                                   cps = (int) (zero.flen / ft);
  1091.                                   i = (connect_rate/100);
  1092.                                   if(i<=0)i=1;
  1093.                                   x = (cps*10) / i;
  1094.                                   curlocat(14,28);
  1095.                                   return_code = 0;
  1096.                                   colrprtf(0,0,7,"%3d%%",x);
  1097.                                   out = fopen(log_file,"a");
  1098.                                   fprintf(out,"%d bps   %-14s   %-7ld   %3d%%\n",connect_rate,zero.fnam,zero.flen,x);
  1099.                                   fclose(out);
  1100.                                   return(1);
  1101.  
  1102.                     }
  1103.                     break;
  1104.          }
  1105.     if(!async_carrier(port)){
  1106.          goto abort;
  1107.          }
  1108.    }
  1109.    goto badblock;
  1110. abort:
  1111.   async_rxflush(port);
  1112.   if(file_position > 0 )
  1113.    {
  1114.     closefil(send);
  1115.     openfil(outname,2,&send);
  1116.     setstamp(send,zero.fdate,zero.ftime);
  1117.     closefil(send);
  1118.     if(delete_aborted_transfers)
  1119.                     unlink(outname);
  1120.    }
  1121.    else
  1122.        return(0);
  1123. }
  1124.  
  1125.  
  1126. readblock(buf,size)             /* read a block of data */
  1127. char *buf;                             /* data buffer */
  1128. int size;
  1129. {
  1130.     register n;
  1131.     unsigned long crc;            /* CRC check values */
  1132.     long t1;  /* short block timeout */
  1133.     int x,c;
  1134.     char *p = buf;
  1135.     char *s = buf;
  1136.  
  1137.     n = 0;
  1138.     c = size;
  1139.  
  1140.     while(n<size)
  1141.     {
  1142.            x = async_rxblk(port,s,c);
  1143.            n+=x,c-=x,s+=x;
  1144.            if(!(async_rxcnt(port)) && n<size)
  1145.              {
  1146.                  t1 = timerset(1000L);
  1147.                  while(!timeup(t1) && !async_rxcnt(port))
  1148.                   {
  1149.                      if(!async_carrier(port)) return(0);
  1150.                  }
  1151.                 if(timeup(t1)) return(0);
  1152.              }/* end if */
  1153.  
  1154.     } /* end while n<size */
  1155.       crc = 0xFFFFFFFF;
  1156.       for(n=0;n<size;n++){
  1157.                   crc = UpdCrc32(((unsigned short) (*p++)), crc);
  1158.                   }
  1159.  
  1160.        for (n = 4; --n >= 0;)
  1161.        {
  1162.          c = com_getc(2);
  1163.          crc = UpdCrc32(c, crc);
  1164.        }
  1165.    if (crc != 0xDEBB20E3)
  1166.       {
  1167.       return(0);
  1168.       }
  1169.       return(1);
  1170. }
  1171.  
  1172.  
  1173. com_putc(int t)
  1174. {
  1175.  
  1176.     if(!async_carrier(port)) return;
  1177.  
  1178.     while((async_tx(port,t)) == R_TXERR)
  1179.     {
  1180.       if(!async_carrier(port)) return;
  1181.     }
  1182.  
  1183.  
  1184. }
  1185.  
  1186. sleep(delay)
  1187. int delay;
  1188. {
  1189. long a;
  1190. a = timerset( (long) (delay * 10L) );
  1191. while(!timeup(a)) ;
  1192. }
  1193.  
  1194. clear_screen()
  1195. {
  1196. int x;
  1197. curlocat(4,28); colrprtf(0,0,7,"%-19s","");
  1198. curlocat(5,28); colrprtf(0,0,7,"%-14s","");
  1199. curlocat(6,28); colrprtf(0,0,7,"%-8s","");
  1200. curlocat(7,28); colrprtf(0,0,7,"%-40s","");
  1201. curlocat(5,58); colrprtf(0,0,7,"%-3s","");
  1202. curlocat(6,58); colrprtf(0,0,7,"%-7s","");
  1203. for(x=1;x<=40;x++)
  1204.  {
  1205.   curlocat(19,(21+x));
  1206.     colrprtf(0,0,7,"▓");
  1207.  }
  1208. }
  1209.  
  1210. get_block_header(char *buf)
  1211. {
  1212.     register n;
  1213.     unsigned long crc;
  1214.     int c,x;
  1215.     long t1;
  1216.     char *s = buf;
  1217.     char *p = buf;
  1218.  
  1219.     n = 0;
  1220.     c = 7;
  1221.  
  1222.     while(n<7)
  1223.     {
  1224.            x = async_rxblk(port,s,c);
  1225.            n+=x,c-=x,s+=x;
  1226.            if(!(async_rxcnt(port)) && n<7)
  1227.              {
  1228.                  t1 = timerset(1000L);
  1229.                  while(!timeup(t1) && !async_rxcnt(port))
  1230.                   {
  1231.                      if(!async_carrier(port)) return(0);
  1232.                   }
  1233.                 if(timeup(t1)) return(0);
  1234.              }/* end if */
  1235.  
  1236.     } /* end while n<7 */
  1237.       crc = 0xFFFFFFFF;
  1238.       for(n=0;n<7;n++){
  1239.                   crc = UpdCrc32(((unsigned short) (*p++)), crc);
  1240.                   }
  1241.  
  1242.        for (n = 4; --n >= 0;)
  1243.        {
  1244.          c = com_getc(2);
  1245.          crc = UpdCrc32(c, crc);
  1246.        }
  1247.  
  1248.    if (crc != 0xDEBB20E3)
  1249.                     return(0);
  1250.  
  1251. return(1);
  1252.  
  1253. }
  1254.  
  1255. send_block_header(char *b)
  1256. {
  1257. register n;
  1258. unsigned long oldcrc;
  1259. /*
  1260.  
  1261. Considerable thought went into making the decision to split the
  1262. header block apart from the actual data block.
  1263.  
  1264. Including it as part of the block would mean that only one CRC
  1265. would have to be sent, but considering that this information is
  1266. critical to the proper reception of the block (size and file
  1267. position), it could then be used for error repositioning and
  1268. restarts without additional code (some computers will be running
  1269. under memory restrictions that IBM Compatibles may not have), and
  1270. finally... I couldn't tell any difference either way, speed wise.
  1271.  
  1272. I elected to go for the additional reliablity and reduced code
  1273. size and keep them apart.
  1274.  
  1275. */
  1276. while(  (async_txblk(port, b, 7)) == R_TXERR) ;
  1277.  
  1278.           oldcrc = 0xFFFFFFFF;
  1279.           for(n=0;n<7;n++){
  1280.                   oldcrc = UpdCrc32(((unsigned short) (*b++)), oldcrc);
  1281.                   }
  1282.           oldcrc = ~oldcrc;
  1283.           for(n=4; --n >=0;)
  1284.            {
  1285.               com_putc((unsigned char) oldcrc);
  1286.               oldcrc >>= 8;
  1287.            }
  1288. }
  1289.  
  1290. get_system_info(char *buf)
  1291. {
  1292.     register n;
  1293.     unsigned long crc;
  1294.     int c,x;
  1295.     long t1;
  1296.     char *s = buf;
  1297.     char *p = buf;
  1298. curlocat(7,28);
  1299. colrprtf(0,0,7,"%-40s","Waiting For System Information");
  1300.  
  1301.     n = 0;
  1302.     c = 128;
  1303.  
  1304.     while(n<128)
  1305.     {
  1306.            x = async_rxblk(port,s,c);
  1307.            n+=x,c-=x,s+=x;
  1308.            if(!(async_rxcnt(port)) && n<128)
  1309.              {
  1310.                  t1 = timerset(1000L);
  1311.                  while(!timeup(t1) && !async_rxcnt(port))
  1312.                   {
  1313.                      if(!async_carrier(port)) return(0);
  1314.                   }
  1315.                 if(timeup(t1)) return(0);
  1316.              }/* end if */
  1317.  
  1318.     } /* end while n<128 */
  1319.       crc = 0xFFFFFFFF;
  1320.       for(n=0;n<128;n++){
  1321.                   crc = UpdCrc32(((unsigned short) (*p++)), crc);
  1322.                   }
  1323.  
  1324.        for (n = 4; --n >= 0;)
  1325.        {
  1326.          c = com_getc(2);
  1327.          crc = UpdCrc32(c, crc);
  1328.        }
  1329.  
  1330.    if (crc != 0xDEBB20E3){
  1331.              com_putc('C');
  1332.              return(0);
  1333.              }
  1334.  
  1335. com_putc(ACK);
  1336. return(1);
  1337. }
  1338.  
  1339. send_system_info(char *b)
  1340. {
  1341. register n;
  1342. int c,attempts=0;
  1343. unsigned long oldcrc;
  1344. char *p;
  1345. curlocat(7,28);
  1346. colrprtf(0,0,7,"%-40s","Sending System Information");
  1347. async_rxflush(port);
  1348. while(async_rxcnt(port)){
  1349.           async_rxflush(port);
  1350.           }
  1351. for(;;)
  1352. {
  1353.  
  1354.          while(  (async_txblk(port, b, 128)) == R_TXERR) ;
  1355.  
  1356.           oldcrc = 0xFFFFFFFF;
  1357.           p = b;
  1358.           for(n=0;n<128;n++){
  1359.                   oldcrc = UpdCrc32(((unsigned short) (*p++)), oldcrc);
  1360.                   }
  1361.           oldcrc = ~oldcrc;
  1362.           for(n=4; --n >=0;)
  1363.            {
  1364.               com_putc((unsigned char) oldcrc);
  1365.               oldcrc >>= 8;
  1366.            }
  1367.            c = com_getc(5);
  1368.            if(c == ACK) return;
  1369.            if(++attempts > 3)
  1370.            {
  1371.                 async_dtr(port,0);
  1372.                 sleep(3);
  1373.                 async_dtr(port,1);
  1374.                 return;
  1375.            }/* Screw it, drop connection and try later */
  1376.  
  1377. }/* End send system info */
  1378.  
  1379. }
  1380. cancel_transfer()
  1381. {
  1382.  
  1383. /* only 5 CAN's needed to abort a session, but I like
  1384.    to send more thans actual needed. */
  1385.  
  1386. com_putc(CAN);
  1387. com_putc(CAN);
  1388. com_putc(CAN);
  1389. com_putc(CAN);
  1390. com_putc(CAN);
  1391. com_putc(CAN);
  1392. com_putc(CAN);
  1393. com_putc(CAN);
  1394. com_putc(CAN);
  1395. com_putc(CAN);
  1396. com_putc(CAN);
  1397. com_putc(CAN);
  1398. com_putc(CAN);
  1399. com_putc(CAN);
  1400. com_putc(CAN);
  1401. com_putc(CAN);
  1402. com_putc(CAN);
  1403. com_putc(CAN);
  1404. com_putc(CAN);
  1405. com_putc(CAN);
  1406. while(!async_txempty(port))
  1407.        if(!async_carrier(port)) break;
  1408. }
  1409.